/*---------------------------------------------------------------------
 * File name: hal_uart.cpp
 *
 * Copyright (c) <2020-2022>, <ChenLong>
 *
 * All rights reserved.
 *
 * Author: ChenLong
 * Email: worldlong@foxmail.com
 *--------------------------------------------------------------------*/
#include "stm32g4xx.h"
#include "buffer/simple_buffer.h"
#include "hal_dma.h"
#include "hal_uart.h"
#include "hal_gpio.h"
#include "hal_system.h"
#include "hal_config.h"
#include "hal_def.h"
#if defined(USING_RT_THREAD)
#include "rtthread.h" 
#endif
/*
*/
static void (*rx_irq_hook[5])(void *param, uint32_t status) = {nullptr};
static void *rx_irq_hook_param[5]={nullptr};
static void (*tx_irq_hook[5])(void *param, uint32_t status) = {nullptr};
static void *tx_irq_hook_param[5]={nullptr};
//UART1 
#if UART1_ENABLE
#if UART1_RX_DMA_ENABLE
#define UART1_RX_DMA_INDEX  (UART1_RX_DMA - DMA1_CHANNEL1)
#if UART1_RX_DMA_INDEX < 0 || UART1_RX_DMA_INDEX > 15
#error "UART1_RX_DMA incorrect"
#endif
#endif

#if UART1_TX_DMA_ENABLE
#define UART1_TX_DMA_INDEX  (UART1_TX_DMA - DMA1_CHANNEL1)
#if UART1_TX_DMA_INDEX < 0 || UART1_TX_DMA_INDEX > 15
#error "UART1_TX_DMA incorrect"
#endif
#endif
#endif

//UART2 
#if UART2_ENABLE
#if UART2_RX_DMA_ENABLE
#define UART2_RX_DMA_INDEX  (UART2_RX_DMA - DMA1_CHANNEL1)
#if UART2_RX_DMA_INDEX < 0 || UART2_RX_DMA_INDEX > 15
#error "UART2_RX_DMA incorrect"
#endif
#endif

#if UART2_TX_DMA_ENABLE
#define UART2_TX_DMA_INDEX  (UART2_TX_DMA - DMA1_CHANNEL1)
#if UART2_TX_DMA_INDEX < 0 || UART2_TX_DMA_INDEX > 15
#error "UART2_TX_DMA incorrect"
#endif
#endif
#endif

//UART3 
#if UART3_ENABLE
#if UART3_RX_DMA_ENABLE
#define UART3_RX_DMA_INDEX  (UART3_RX_DMA - DMA1_CHANNEL1)
#if UART3_RX_DMA_INDEX < 0 || UART3_RX_DMA_INDEX > 15
#error "UART3_RX_DMA incorrect"
#endif
#endif

#if UART3_TX_DMA_ENABLE
#define UART3_TX_DMA_INDEX  (UART3_TX_DMA - DMA1_CHANNEL1)
#if UART3_TX_DMA_INDEX < 0 || UART3_TX_DMA_INDEX > 15
#error "UART3_TX_DMA incorrect"
#endif
#endif
#endif

//UART4 
#if UART4_ENABLE
#if UART4_RX_DMA_ENABLE
#define UART4_RX_DMA_INDEX  (UART4_RX_DMA - DMA1_CHANNEL1)
#if UART4_RX_DMA_INDEX < 0 || UART4_RX_DMA_INDEX > 15
#error "UART4_RX_DMA incorrect"
#endif
#endif

#if UART4_TX_DMA_ENABLE
#define UART4_TX_DMA_INDEX  (UART4_TX_DMA - DMA1_CHANNEL1)
#if UART4_TX_DMA_INDEX < 0 || UART4_TX_DMA_INDEX > 15
#error "UART4_TX_DMA incorrect"
#endif
#endif
#endif

//UART5 
#if UART5_ENABLE
#if UART5_RX_DMA_ENABLE
#define UART5_RX_DMA_INDEX  (UART5_RX_DMA - DMA1_CHANNEL1)
#if UART5_RX_DMA_INDEX < 0 || UART5_RX_DMA_INDEX > 15
#error "UART5_RX_DMA incorrect"
#endif
#endif

#if UART5_TX_DMA_ENABLE
#define UART5_TX_DMA_INDEX  (UART5_TX_DMA - DMA1_CHANNEL1)
#if UART5_TX_DMA_INDEX < 0 || UART5_TX_DMA_INDEX > 15
#error "UART5_TX_DMA incorrect"
#endif
#endif
#endif

/*---------------------------------------------------
 *                   UART_Object
 *---------------------------------------------------*/
#define DMA_ENABLE(dma_ch)  REG_BIT_SET(dma_ch->CCR, 0)
#define DMA_DISABLE(dma_ch) REG_BIT_CLEAR(dma_ch->CCR, 0)
/*
*/
class UART_Object
{
public:
  UART_Object(int index0,
              USART_TypeDef *USARTx,
              int dma_rx_ch_index0,
              int dma_tx_ch_index0,
              uint8_t *dma_rx_buffer0, int dma_rx_buffer_size0,
              uint8_t *dma_tx_buffer0, int dma_tx_buffer_size0,
              SimpleBuffer<uint8_t> &rx_buffer0,
              SimpleBuffer<uint8_t> &tx_buffer0) :
    index(index0),
    dma_rx_ch_index(dma_rx_ch_index0),
    dma_tx_ch_index(dma_tx_ch_index0),
    uart(USARTx),
    dma_rx_buffer(dma_rx_buffer0),
    dma_tx_buffer(dma_tx_buffer0),
    dma_rx_buffer_size(dma_rx_buffer_size0),
    dma_tx_buffer_size(dma_tx_buffer_size0),
    rx_buffer(rx_buffer0),
    tx_buffer(tx_buffer0),
    rx_busy(false),
    tx_busy(false)
  {
    dma_rx = (DMA_Channel_TypeDef*)HAL_DMA::get_channel(dma_rx_ch_index);
    dma_tx = (DMA_Channel_TypeDef*)HAL_DMA::get_channel(dma_tx_ch_index);
  }
  
  int index;
  int dma_rx_ch_index;
  int dma_tx_ch_index;
  USART_TypeDef         *uart;
  DMA_Channel_TypeDef   *dma_rx;
  DMA_Channel_TypeDef   *dma_tx;
  uint8_t *dma_rx_buffer;
  uint8_t *dma_tx_buffer;
  int dma_rx_buffer_size;
  int dma_tx_buffer_size;
  SimpleBuffer<uint8_t> &rx_buffer;
  SimpleBuffer<uint8_t> &tx_buffer;
  bool rx_busy;
  bool tx_busy;
  
  void dma_rx_config();
  void dma_rx_start();
  void dma_rx_end();
  void dma_tx_config();
  void dma_tx_start();
  void dma_tx_end();
  void int_rx_config();
  void int_tx_config();
  void int_rx();
  void int_tx();
  void send();
  bool config(uint32_t cfg);
};
/*
*/
static void dma_tx_irq_hook(void *param, uint32_t status)
{
  UART_Object *dev = (UART_Object*)param;
  dev->dma_tx_end();
  dev->dma_tx_start();  //transfer residual data
  if(tx_irq_hook[dev->index] != nullptr) {
    tx_irq_hook[dev->index](tx_irq_hook_param[dev->index], status);
  }
}
/*
*/
void UART_Object::dma_rx_config()
{
    DMA_DISABLE(dma_rx);  //disable first
  
    DMA_HandleTypeDef  hdma;
    hdma.Instance = dma_rx;
    if(uart == USART1) {
      hdma.Init.Request = DMA_REQUEST_USART1_RX;
    } else if(uart == USART2) {
      hdma.Init.Request = DMA_REQUEST_USART2_RX;
    } else if(uart == USART3) {
      hdma.Init.Request = DMA_REQUEST_USART3_RX;
    } else if(uart == UART4) {
      hdma.Init.Request = DMA_REQUEST_UART4_RX;
    } else if(uart == UART5) {
      hdma.Init.Request = DMA_REQUEST_UART5_RX;
    }
    hdma.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma.Init.MemInc = DMA_MINC_ENABLE;
    hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma.Init.Mode = DMA_NORMAL;
    hdma.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma) != HAL_OK)
    {
      return;
    }
    dma_rx->CMAR = (uint32_t)dma_rx_buffer;
    dma_rx->CPAR = (uint32_t)&uart->RDR;
    dma_rx->CCR &= ~(BIT(3)|BIT(2)|BIT(1));   //Disable all interrupt
    
    uart->CR3 |= BIT(6);  //Enable UART DMA Rx
    uart->CR1 |= BIT(4);  //Enable UART IDLIE
}
/*
*/
void UART_Object::dma_tx_config()
{
    DMA_DISABLE(dma_tx);  //disable first
    
    DMA_HandleTypeDef  hdma;
    hdma.Instance = dma_tx;
    if(uart == USART1) {
      hdma.Init.Request = DMA_REQUEST_USART1_TX;
    } else if(uart == USART2) {
      hdma.Init.Request = DMA_REQUEST_USART2_TX;
    } else if(uart == USART3) {
      hdma.Init.Request = DMA_REQUEST_USART3_TX;
    } else if(uart == UART4) {
      hdma.Init.Request = DMA_REQUEST_UART4_TX;
    } else if(uart == UART5) {
      hdma.Init.Request = DMA_REQUEST_UART5_TX;
    }
    hdma.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma.Init.MemInc = DMA_MINC_ENABLE;
    hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma.Init.Mode = DMA_NORMAL;
    hdma.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma) != HAL_OK)
    {
      return;
    }
    dma_tx->CMAR = (uint32_t)dma_tx_buffer;
    dma_tx->CPAR = (uint32_t)&uart->TDR;
    dma_tx->CCR &= ~(BIT(3)|BIT(2)|BIT(1)); 
    dma_tx->CCR |= BIT(3)|BIT(1);   //Enable TEIE and TCIE, diable HTIE
    
    uart->CR3 |= BIT(7);  //Enable UART DMA Tx
    
    //Set DMA irq_hook
    HAL_DMA::set_irq_hook(dma_tx_ch_index, dma_tx_irq_hook, this);
}
/*
*/
void UART_Object::dma_tx_start()
{
  if(!tx_busy)
  {
    uint32_t sr = enter_critical();
    int number = tx_buffer.pop(dma_tx_buffer, dma_tx_buffer_size);
    exit_critical(sr);
    
    if(number > 0)
    {
      tx_busy = true;
      dma_tx->CNDTR = number;
      DMA_ENABLE(dma_tx);
    }
  }
}
/*
*/
void UART_Object::dma_tx_end()
{
  DMA_DISABLE(dma_tx);
  tx_busy = false;
}
/*
*/
void UART_Object::dma_rx_start()
{
  if(!rx_busy)
  {
    rx_busy = true;
    dma_rx->CNDTR = dma_rx_buffer_size;
    DMA_ENABLE(dma_rx);
  }
}
/*
*/
void UART_Object::dma_rx_end()
{
  DMA_DISABLE(dma_rx);
  int number = dma_rx_buffer_size - dma_rx->CNDTR;
  
  uint32_t sr = enter_critical();
  rx_buffer.push(dma_rx_buffer, number);
  exit_critical(sr);
  
  rx_busy = false;
}
/*
*/
void UART_Object::int_rx_config()
{
  dma_rx_buffer_size = uart->RDR;  //clear RXNE flag
  uart->CR3 &= ~BIT(6);            //Disable UART DMA Rx
  uart->CR1 |= BIT(4)|BIT(5);      //Enable UART IDLIE and RXFNE
}
/*
*/
void UART_Object::int_tx_config()
{
  uart->CR1 &= ~BIT(7);  //Disable TXFNF first
}
/*
*/
void UART_Object::int_rx()
{
  uint8_t data = uart->RDR;
  
  uint32_t sr = enter_critical();
  rx_buffer.push(&data, 1);
  exit_critical(sr);
}
/*
*/
void UART_Object::int_tx()
{
  uint8_t data;
  
  uint32_t sr = enter_critical();
  int number = tx_buffer.pop(&data, 1);
  exit_critical(sr);
  
  if(number > 0) {
    uart->TDR = data;
  } else {
    uart->CR1 &= ~BIT(7);  //Disable TXFNF
  }
}
/*
*/
void UART_Object::send()
{
  if(dma_tx_buffer != nullptr) {
    dma_tx_start();
  } else {
    uart->CR1 |= BIT(7);  //Enable TXFNF
  }
}
/*
*/
bool UART_Object::config(uint32_t cfg)
{
  UART_HandleTypeDef huart;
  
  huart.Instance = uart;
  
  //baud
  uint32_t tmp = HUART_CFG_EXTRACT(cfg, BAUD);
  huart.Init.BaudRate = tmp;
  
  //data bits
  tmp = HUART_CFG_EXTRACT(cfg, DATA);
  if(tmp == HUART_DATA(8B)) {
    huart.Init.WordLength = UART_WORDLENGTH_8B;
  } else if (tmp == HUART_DATA(9B)) {
    huart.Init.WordLength = UART_WORDLENGTH_9B;
  } else {
    return false;
  }
  
  //parity
  tmp = HUART_CFG_EXTRACT(cfg, PARITY);
  if(tmp == HUART_PARITY(NONE)) {
    huart.Init.Parity = UART_PARITY_NONE;
  } else if(tmp == HUART_PARITY(ODD)) {
    huart.Init.Parity = UART_PARITY_ODD;
  } else if(tmp == HUART_PARITY(EVEN)) {
    huart.Init.Parity = UART_PARITY_EVEN;
  } else {
    return false;
  }
   
  //stop bits
  tmp = HUART_CFG_EXTRACT(cfg, STOP);
  if(tmp == HUART_STOP(1B)) {
    huart.Init.StopBits = UART_STOPBITS_1;  
  } else if(tmp == HUART_STOP(1B5)) {
    huart.Init.StopBits = UART_STOPBITS_1_5;   
  } else if(tmp == HUART_STOP(2B)) {
    huart.Init.StopBits = UART_STOPBITS_2;  
  } else {
    return false;
  }
  
  huart.Init.Mode = UART_MODE_TX_RX;
  huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart.Init.OverSampling = UART_OVERSAMPLING_16;
  huart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  
  if (HAL_UART_Init(&huart) != HAL_OK)
  {
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
  }
  if (HAL_UARTEx_DisableFifoMode(&huart) != HAL_OK)
  {
  }
  
  uart->CR1 |= BIT(2)|BIT(3); //Enable Tx and Rx
  return true;
}

/*----------------------------------------
 *             UART1 Object
 *-----------------------------------------*/
#if UART1_ENABLE
#if UART1_RX_DMA_ENABLE
  static uint8_t uart1_rx_dma_buffer[UART1_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart1_rx_dma_buffer = nullptr;
#endif
#if UART1_TX_DMA_ENABLE
  static uint8_t uart1_tx_dma_buffer[UART1_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart1_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart1_rx_buffer[UART1_RX_BUFFER_SIZE];
  static uint8_t uart1_tx_buffer[UART1_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart1_rx_sbuffer(uart1_rx_buffer, UART1_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart1_tx_sbuffer(uart1_tx_buffer, UART1_TX_BUFFER_SIZE);
  static UART_Object uart1(0, USART1, 
                           UART1_RX_DMA_INDEX, 
                           UART1_TX_DMA_INDEX,
                           uart1_rx_dma_buffer, UART1_RX_DMA_BUFFER_SIZE,
                           uart1_tx_dma_buffer, UART1_TX_DMA_BUFFER_SIZE,
                           uart1_rx_sbuffer,
                           uart1_tx_sbuffer);
#endif
/*----------------------------------------
 *             UART2 Object
 *-----------------------------------------*/
#if UART2_ENABLE
#if UART2_RX_DMA_ENABLE
  static uint8_t uart2_rx_dma_buffer[UART2_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart2_rx_dma_buffer = nullptr;
#endif
#if UART2_TX_DMA_ENABLE
  static uint8_t uart2_tx_dma_buffer[UART2_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart2_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart2_rx_buffer[UART2_RX_BUFFER_SIZE];
  static uint8_t uart2_tx_buffer[UART2_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart2_rx_sbuffer(uart2_rx_buffer, UART2_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart2_tx_sbuffer(uart2_tx_buffer, UART2_TX_BUFFER_SIZE);
  static UART_Object uart2(1, USART2, 
                           UART2_RX_DMA_INDEX, 
                           UART2_TX_DMA_INDEX,
                           uart2_rx_dma_buffer, UART2_RX_DMA_BUFFER_SIZE,
                           uart2_tx_dma_buffer, UART2_TX_DMA_BUFFER_SIZE,
                           uart2_rx_sbuffer,
                           uart2_tx_sbuffer);
#endif
/*----------------------------------------
 *             UART3 Object
 *-----------------------------------------*/
#if UART3_ENABLE
#if UART3_RX_DMA_ENABLE
  static uint8_t uart3_rx_dma_buffer[UART3_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart3_rx_dma_buffer = nullptr;
#endif
#if UART3_TX_DMA_ENABLE
  static uint8_t uart3_tx_dma_buffer[UART3_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart3_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart3_rx_buffer[UART3_RX_BUFFER_SIZE];
  static uint8_t uart3_tx_buffer[UART3_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart3_rx_sbuffer(uart3_rx_buffer, UART3_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart3_tx_sbuffer(uart3_tx_buffer, UART3_TX_BUFFER_SIZE);
  static UART_Object uart3(2, USART3, 
                           UART3_RX_DMA_INDEX, 
                           UART3_TX_DMA_INDEX,
                           uart3_rx_dma_buffer, UART3_RX_DMA_BUFFER_SIZE,
                           uart3_tx_dma_buffer, UART3_TX_DMA_BUFFER_SIZE,
                           uart3_rx_sbuffer,
                           uart3_tx_sbuffer);
#endif
/*----------------------------------------
 *             UART4 Object
 *-----------------------------------------*/
#if UART4_ENABLE
#if UART4_RX_DMA_ENABLE
  static uint8_t uart4_rx_dma_buffer[UART4_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart4_rx_dma_buffer = nullptr;
#endif
#if UART4_TX_DMA_ENABLE
  static uint8_t uart4_tx_dma_buffer[UART4_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart4_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart4_rx_buffer[UART4_RX_BUFFER_SIZE];
  static uint8_t uart4_tx_buffer[UART4_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart4_rx_sbuffer(uart4_rx_buffer, UART4_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart4_tx_sbuffer(uart4_tx_buffer, UART4_TX_BUFFER_SIZE);
  static UART_Object uart4(3, UART4, 
                           UART4_RX_DMA_INDEX, 
                           UART4_TX_DMA_INDEX,
                           uart4_rx_dma_buffer, UART4_RX_DMA_BUFFER_SIZE,
                           uart4_tx_dma_buffer, UART4_TX_DMA_BUFFER_SIZE,
                           uart4_rx_sbuffer,
                           uart4_tx_sbuffer);
#endif
/*----------------------------------------
 *             UART5 Object
 *-----------------------------------------*/
#if UART5_ENABLE
#if UART5_RX_DMA_ENABLE
  static uint8_t uart5_rx_dma_buffer[UART5_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart5_rx_dma_buffer = nullptr;
#endif
#if UART5_TX_DMA_ENABLE
  static uint8_t uart5_tx_dma_buffer[UART5_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart5_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart5_rx_buffer[UART5_RX_BUFFER_SIZE];
  static uint8_t uart5_tx_buffer[UART5_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart5_rx_sbuffer(uart5_rx_buffer, UART5_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart5_tx_sbuffer(uart5_tx_buffer, UART5_TX_BUFFER_SIZE);
  static UART_Object uart5(4, UART5, 
                           UART5_RX_DMA_INDEX, 
                           UART5_TX_DMA_INDEX,
                           uart5_rx_dma_buffer, UART5_RX_DMA_BUFFER_SIZE,
                           uart5_tx_dma_buffer, UART5_TX_DMA_BUFFER_SIZE,
                           uart5_rx_sbuffer,
                           uart5_tx_sbuffer);
#endif


/**********************************
 *         HAL_UART
 **********************************/
bool HAL_UART::init(uint32_t cfg0)
{
  uint8_t rx_nvic_irqn = 0;
  uint8_t tx_nvic_irqn = 0;
  uint8_t nvic_prio = 0;
  
  cfg = cfg0;
  uint32_t tmp = HUART_CFG_EXTRACT(cfg, PORT);
  if(tmp == 0) {  //No port
   return false;
  }
  //UART1
#if UART1_ENABLE
  else if(tmp == HUART_PORT(1)) {
    port = (uint32_t)&uart1;
    nvic_prio = NVIC_IRQ_UART1_PRIORITY;
    rx_nvic_irqn = USART1_IRQn;
    //Rx
#if UART1_RX_DMA_ENABLE
    uart1.dma_rx_config();
    uart1.dma_rx_start();
#else
    uart1.int_rx_config();
#endif
    //Tx
#if UART1_TX_DMA_ENABLE
    uart1.dma_tx_config();
    tx_nvic_irqn = (IRQn_Type)HAL_DMA::get_irqn(uart1.dma_tx_ch_index);
#else
    uart1.int_tx_config();  //Not DMA mode, just keep tx_nvic_irqn = 0, because it's same to rx_nvic_irqn
#endif
  }
#endif
  
    //UART2
#if UART2_ENABLE
  else if(tmp == HUART_PORT(2)) {
    port = (uint32_t)&uart2;
    nvic_prio = NVIC_IRQ_UART2_PRIORITY;
    rx_nvic_irqn = USART2_IRQn;
    //Rx
#if UART2_RX_DMA_ENABLE
    uart2.dma_rx_config();
    uart2.dma_rx_start();
#else
    uart2.int_rx_config();
#endif
    //Tx
#if UART2_TX_DMA_ENABLE
    uart2.dma_tx_config();
    tx_nvic_irqn = (IRQn_Type)HAL_DMA::get_irqn(uart2.dma_tx_ch_index);
#else
    uart2.int_tx_config();  //Not DMA mode, just keep tx_nvic_irqn = 0, because it's same to rx_nvic_irqn
#endif
  }
#endif
  
  //UART3
#if UART3_ENABLE
  else if(tmp == HUART_PORT(3)) {
    port = (uint32_t)&uart3;
    nvic_prio = NVIC_IRQ_UART3_PRIORITY;
    rx_nvic_irqn = USART3_IRQn;
    //Rx
#if UART3_RX_DMA_ENABLE
    uart3.dma_rx_config();
    uart3.dma_rx_start();
#else
    uart3.int_rx_config();
#endif
    //Tx
#if UART3_TX_DMA_ENABLE
    uart3.dma_tx_config();
    tx_nvic_irqn = (IRQn_Type)HAL_DMA::get_irqn(uart3.dma_tx_ch_index);
#else
    uart3.int_tx_config();  //Not DMA mode, just keep tx_nvic_irqn = 0, because it's same to rx_nvic_irqn
#endif
  }
#endif
  
  //UART4
#if UART4_ENABLE
  else if(tmp == HUART_PORT(4)) {
    port = (uint32_t)&uart4;
    nvic_prio = NVIC_IRQ_UART4_PRIORITY;
    rx_nvic_irqn = UART4_IRQn;
    //Rx
#if UART4_RX_DMA_ENABLE
    uart4.dma_rx_config();
    uart4.dma_rx_start();
#else
    uart4.int_rx_config();
#endif
    //Tx
#if UART4_TX_DMA_ENABLE
    uart4.dma_tx_config();
    tx_nvic_irqn = (IRQn_Type)HAL_DMA::get_irqn(uart4.dma_tx_ch_index);
#else
    uart4.int_tx_config();  //Not DMA mode, just keep tx_nvic_irqn = 0, because it's same to rx_nvic_irqn
#endif
  }
#endif
  
  //UART5
#if UART5_ENABLE
  else if(tmp == HUART_PORT(5)) {
    port = (uint32_t)&uart5;
    nvic_prio = NVIC_IRQ_UART5_PRIORITY;
    rx_nvic_irqn = UART5_IRQn;
    //Rx
#if UART5_RX_DMA_ENABLE
    uart5.dma_rx_config();
    uart5.dma_rx_start();
#else
    uart5.int_rx_config();
#endif
    //Tx
#if UART5_TX_DMA_ENABLE
    uart5.dma_tx_config();
    tx_nvic_irqn = (IRQn_Type)HAL_DMA::get_irqn(uart5.dma_tx_ch_index);
#else
    uart5.int_tx_config();  //Not DMA mode, just keep tx_nvic_irqn = 0, because it's same to rx_nvic_irqn
#endif
  }
#endif
  else {
    return false;
  }
  
  if(!config(cfg)) {
    return false;
  }
  
  //NVIC config
  //rx
  if(rx_nvic_irqn > 0) {
    HAL_NVIC_SetPriority((IRQn_Type)rx_nvic_irqn, nvic_prio, 0);
    HAL_NVIC_EnableIRQ((IRQn_Type)rx_nvic_irqn);
  }
  //tx
  if(tx_nvic_irqn > 0) {
    HAL_NVIC_SetPriority((IRQn_Type)tx_nvic_irqn, nvic_prio, 0);
    HAL_NVIC_EnableIRQ((IRQn_Type)tx_nvic_irqn);
  }
  return true;
}
/*
*/
bool HAL_UART::config(uint32_t cfg0)
{
  cfg &= ~HUART_CFG_MASK;
  cfg |= cfg0 & HUART_CFG_MASK;
  return ((UART_Object*)port)->config(cfg);
}
/*
*/
int HAL_UART::read(uint8_t *buffer, uint32_t num)
{
  return ((UART_Object*)port)->rx_buffer.pop(buffer, num);
}
/*
*/
int HAL_UART::write(uint8_t *buffer, uint32_t num)
{
  int ret = ((UART_Object*)port)->tx_buffer.push(buffer, num);
  ((UART_Object*)port)->send();
  return ret;
}
/*
*/
int HAL_UART::write(uint8_t *buffer, uint32_t num, uint32_t ms)
{
  while(((UART_Object*)port)->tx_buffer.full_check(num)) {
#if defined(USING_RT_THREAD)
  rt_thread_mdelay(ms);
#endif
  }
  int ret = ((UART_Object*)port)->tx_buffer.push(buffer, num);
  ((UART_Object*)port)->send();
  return ret;
}
/*------------------------------------------------
 *             IRQHandler
 *------------------------------------------------*/
#ifdef __cplusplus
 extern "C" {
#endif
/*
*/
#if UART1_ENABLE
void USART1_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  uint32_t status = uart1.uart->ISR;
  //rx
  if(status & BIT(4)) {     //IDL means Rx end
    uart1.uart->ICR |= BIT(4);  //clear
#if UART1_RX_DMA_ENABLE    
    uart1.dma_rx_end();
    uart1.dma_rx_start();
#endif
    if(rx_irq_hook[uart1.index] != nullptr) {
      rx_irq_hook[uart1.index](rx_irq_hook_param[uart1.index], status);
    }
  }
#if !UART1_RX_DMA_ENABLE
  if(status & BIT(5)) {  //RXFNE
    uart1.int_rx();
  }
#endif
  
  //tx
#if !UART1_TX_DMA_ENABLE
  if(status & BIT(7)) {  //TXFNF
    if(uart1.int_tx() == 0 && tx_irq_hook[uart1.index] != nullptr) { //Tx end
        tx_irq_hook[uart1.index](tx_irq_hook_param[uart1.index], status);
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif

/*
*/
#if UART2_ENABLE
void USART2_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  uint32_t status = uart2.uart->ISR;
  //rx
  if(status & BIT(4)) {     //IDL means Rx end
    uart2.uart->ICR |= BIT(4);  //clear
#if UART2_RX_DMA_ENABLE    
    uart2.dma_rx_end();
    uart2.dma_rx_start();
#endif
    if(rx_irq_hook[uart2.index] != nullptr) {
      rx_irq_hook[uart2.index](rx_irq_hook_param[uart2.index], status);
    }
  }
#if !UART2_RX_DMA_ENABLE
  if(status & BIT(5)) {  //RXFNE
    uart2.int_rx();
  }
#endif
  
  //tx
#if !UART2_TX_DMA_ENABLE
  if(status & BIT(7)) {  //TXFNF
    if(uart2.int_tx() == 0 && tx_irq_hook[uart2.index] != nullptr) { //Tx end
        tx_irq_hook[uart2.index](tx_irq_hook_param[uart2.index], status);
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
/*
*/
#if UART3_ENABLE
void USART3_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  uint32_t status = uart3.uart->ISR;
  //rx
  if(status & BIT(4)) {     //IDL means Rx end
    uart3.uart->ICR |= BIT(4);  //clear
#if UART3_RX_DMA_ENABLE    
    uart3.dma_rx_end();
    uart3.dma_rx_start();
#endif
    if(rx_irq_hook[uart3.index] != nullptr) {
      rx_irq_hook[uart3.index](rx_irq_hook_param[uart3.index], status);
    }
  }
#if !UART3_RX_DMA_ENABLE
  if(status & BIT(5)) {  //RXFNE
    uart3.int_rx();
  }
#endif
  
  //tx
#if !UART3_TX_DMA_ENABLE
  if(status & BIT(7)) {  //TXFNF
    if(uart3.int_tx() == 0 && tx_irq_hook[uart3.index] != nullptr) { //Tx end
        tx_irq_hook[uart3.index](tx_irq_hook_param[uart3.index], status);
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
/*
*/
#if UART4_ENABLE
void USART4_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  uint32_t status = uart4.uart->ISR;
  //rx
  if(status & BIT(4)) {     //IDL means Rx end
    uart4.uart->ICR |= BIT(4);  //clear
#if UART4_RX_DMA_ENABLE    
    uart4.dma_rx_end();
    uart4.dma_rx_start();
#endif
    if(rx_irq_hook[uart4.index] != nullptr) {
      rx_irq_hook[uart4.index](rx_irq_hook_param[uart4.index], status);
    }
  }
#if !UART4_RX_DMA_ENABLE
  if(status & BIT(5)) {  //RXFNE
    uart4.int_rx();
  }
#endif
  
  //tx
#if !UART4_TX_DMA_ENABLE
  if(status & BIT(7)) {  //TXFNF
    if(uart4.int_tx() == 0 && tx_irq_hook[uart4.index] != nullptr) { //Tx end
        tx_irq_hook[uart4.index](tx_irq_hook_param[uart4.index], status);
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
/*
*/
#if UART5_ENABLE
void USART5_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  uint32_t status = uart5.uart->ISR;
  //rx
  if(status & BIT(4)) {     //IDL means Rx end
    uart5.uart->ICR |= BIT(4);  //clear
#if UART5_RX_DMA_ENABLE    
    uart5.dma_rx_end();
    uart5.dma_rx_start();
#endif
    if(rx_irq_hook[uart5.index] != nullptr) {
      rx_irq_hook[uart5.index](rx_irq_hook_param[uart5.index], status);
    }
  }
#if !UART5_RX_DMA_ENABLE
  if(status & BIT(5)) {  //RXFNE
    uart5.int_rx();
  }
#endif
  
  //tx
#if !UART5_TX_DMA_ENABLE
  if(status & BIT(7)) {  //TXFNF
    if(uart5.int_tx() == 0 && tx_irq_hook[uart5.index] != nullptr) { //Tx end
        tx_irq_hook[uart5.index](tx_irq_hook_param[uart5.index], status);
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
/*
*/
#ifdef __cplusplus
}
#endif

